﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using élénkPróbája.helpers;
using élénkPróbája.results;

namespace élénkPróbája.validators
{
    public class DelegatingValidator : ILitDelegatingValidator
    {
        private readonly Func<object, bool> condition;
        private readonly Func<object, Task<bool>> asyncCondition;
        public ILitPropertyValidator InnerValidator { get; private set; }

        public virtual bool IsAsync
        {
            get { return InnerValidator.IsAsync || asyncCondition != null; }
        }

        public DelegatingValidator(Func<object, bool> condition, ILitPropertyValidator innerValidator)
        {
            this.condition = condition;
            this.asyncCondition = null;
            InnerValidator = innerValidator;
        }

        public DelegatingValidator(Func<object, Task<bool>> asyncCondition, ILitPropertyValidator innerValidator)
        {
            this.condition = _ => true;
            this.asyncCondition = asyncCondition;
            InnerValidator = innerValidator;
        }

        public IStringSource ErrorMessageSource
        {
            get { return InnerValidator.ErrorMessageSource; }
            set { InnerValidator.ErrorMessageSource = value; }
        }

        public IStringSource ErrorCodeSource
        {
            get { return InnerValidator.ErrorCodeSource; }
            set { InnerValidator.ErrorCodeSource = value; }
        }

        public IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context)
        {
            if (condition(context.Instance))
            {
                return InnerValidator.Validate(context);
            }
            return Enumerable.Empty<ValidationFailure>();
        }

        public Task<IEnumerable<ValidationFailure>> ValidateAsync(PropertyValidatorContext context, CancellationToken cancellation)
        {
            if (!condition(context.Instance))
                return TaskHelpers.FromResult(Enumerable.Empty<ValidationFailure>());

            if (asyncCondition == null)
                return InnerValidator.ValidateAsync(context, cancellation);

            return asyncCondition(context.Instance)
                .Then(shouldValidate =>
                    shouldValidate
                        ? InnerValidator.ValidateAsync(context, cancellation)
                        : TaskHelpers.FromResult(Enumerable.Empty<ValidationFailure>()),
                    runSynchronously: true);
        }

        public ICollection<Func<object, object, object>> CustomMessageFormatArguments
        {
            get { return InnerValidator.CustomMessageFormatArguments; }
        }

        public bool SupportsStandaloneValidation
        {
            get { return false; }
        }

        public Func<object, object> CustomStateProvider
        {
            get { return InnerValidator.CustomStateProvider; }
            set { InnerValidator.CustomStateProvider = value; }
        }

        ILitPropertyValidator ILitDelegatingValidator.InnerValidator
        {
            get { return InnerValidator; }
        }

        public bool CheckCondition(object instance)
        {
            return condition(instance);
        }
    }
}